#include "Common.h"
#include "App_Files.h"

#include <fcntl.h>

/**********************************************************
 * Function Name:        AppFile_Write
 * Description:          向文件中写入数据
 * Parameters[in]:       IN SINT32 fd
 *                       IN void *data
 *                       IN SINT32 len
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.04.29
***********************************************************/
ULONG AppFile_Write(IN SINT32 fd, IN void *data, IN SINT32 len)
{
    ssize_t iTotalSend = 0;
    ssize_t iWriteSize = len;

    while (iTotalSend < len && fd >= 0)
    {
        iWriteSize = write(fd, data + iTotalSend, iWriteSize);
        if (iWriteSize <= 0)
        {
            if (iWriteSize < 0 && errno == EINTR)
            {
                iWriteSize = 0;
            }
            else
            {
                LOG_ERROR("write error %s\n", strerror(errno));
                return STAT_ERR_FILE_WRITE;
            }
        }

        iTotalSend += iWriteSize;

        iWriteSize = len - iTotalSend;
    }

    return STAT_SUCCESS;
}

/**********************************************************
 * Function Name:        AppFile_Read
 * Description:          从文件中读出数据
 * Parameters[in]:       IN SINT32 fd
 *                       INOUT void *data
 *                       IN SINT32 iTotalSize
 * Parameters[out]:      INOUT void *data
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.04.29
***********************************************************/
ULONG AppFile_Read(IN SINT32 fd, INOUT void *data, IN SINT32 iTotalSize)
{
    ssize_t iTotalRecv = 0;
    ssize_t iReadSize = iTotalSize;

    while (iTotalRecv < iTotalSize)
    {
        iReadSize = read(fd, data + iTotalRecv, iReadSize);
        if (iReadSize == 0)
        {
            break;
        }
        else if (iReadSize < 0)
        {
            if (errno == EINTR)
            {
                iReadSize = 0;
            }
            else
            {
                LOG_ERROR("read error %s\n", strerror(errno));
                return STAT_ERR_FILE_READ;
            }
        }

        iTotalRecv += iReadSize;

        iReadSize = iTotalSize - iTotalRecv;
    }

    return STAT_SUCCESS;
}

/**********************************************************
 * Function Name:        AppFile_setLock
 * Description:          设置文件锁
 * Parameters[in]:       IN SINT32 fd
 *                       IN struct flock lock
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_setLock(IN SINT32 fd, IN SINT32 cmd,IN struct flock lock)
{
    int ret = 0;

	ret = fcntl(fd, cmd, &lock);
    if (ret < 0)
    {
        if (errno == EACCES || errno == EAGAIN ) 
        {
            return STAT_ERR_FILE_LOCK_BUSY;
        }

        return STAT_ERR_FILE_FCNTL;
    }

	return STAT_SUCCESS;
}

/**********************************************************
 * Function Name:        AppFile_wrlock_block
 * Description:          设置阻塞写锁
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_wrlock_block(IN SINT32 fd)
{
	struct flock lock;

    memset(&lock, 0, sizeof(lock));
	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;

	return AppFile_setLock(fd, F_SETLKW, lock);;
}

/**********************************************************
 * Function Name:        AppFile_wrlock_nonblock
 * Description:          设置非阻塞写锁
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_wrlock_nonblock(IN SINT32 fd)
{
	struct flock lock;

    memset(&lock, 0, sizeof(lock));
	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;

	return AppFile_setLock(fd, F_SETLK, lock);;
}

/**********************************************************
 * Function Name:        AppFile_rdlock_block
 * Description:          设置文件阻塞读锁
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_rdlock_block(IN SINT32 fd)
{
	struct flock lock;

    memset(&lock, 0, sizeof(lock));
	lock.l_type = F_RDLCK;
	lock.l_whence = SEEK_SET;

	return AppFile_setLock(fd, F_SETLKW, lock);
}

/**********************************************************
 * Function Name:        AppFile_rdlock_nonblock
 * Description:          设置文件非阻塞读锁
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_rdlock_nonblock(IN SINT32 fd)
{
	struct flock lock;

    memset(&lock, 0, sizeof(lock));
	lock.l_type = F_RDLCK;
	lock.l_whence = SEEK_SET;

	return AppFile_setLock(fd, F_SETLK, lock);
}

/**********************************************************
 * Function Name:        AppFile_unlock
 * Description:          释放文件锁
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
 * Note:                 只有加锁才能解锁，避免一直等待，使用非阻塞解锁
***********************************************************/
ULONG AppFile_unlock(IN SINT32 fd)
{
	struct flock lock;
	lock.l_type = F_UNLCK;
	lock.l_whence = SEEK_SET;

	return AppFile_setLock(fd, F_SETLK, lock);
}

/**********************************************************
 * Function Name:        AppFile_writeStr
 * Description:          文件写入字符串
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
 * Note:                 适用于写内存中文件
***********************************************************/
ULONG AppFile_writeStr(const CHAR *pcFileName, const CHAR * value)
{
    SINT32 fd = -1;
    SINT32 iRet = 0;

    fd = open(pcFileName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if(fd < 0)
    {
        LOG_ERROR("open %s fail, Error %s\n", pcFileName, strerror(errno));
        return STAT_ERR_FILE_OPEN;
    }

    AppFile_wrlock_block(fd);
    iRet = write(fd, value, strlen(value));
    AppFile_unlock(fd);
    close(fd);

    if (iRet != strlen(value))
    {
        LOG_ERROR("write %s fail, Error %s\n", pcFileName, strerror(errno));
        return STAT_ERR_FILE_WRITE;
    }

    return STAT_SUCCESS;
}

/**********************************************************
 * Function Name:        AppFile_writeInt32
 * Description:          文件写入32位整型
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_writeInt32(const CHAR *pcFileName, SINT32 value)
{
    CHAR szValue[64] = {0};

    snprintf(szValue, sizeof(szValue), "%d", value);

    return AppFile_writeStr(pcFileName, szValue);
}

/**********************************************************
 * Function Name:        AppFile_writeInt64
 * Description:          文件写入32位整型
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_writeInt64(const CHAR *pcFileName, SINT64 value)
{
    CHAR szValue[64] = {0};

    snprintf(szValue, sizeof(szValue), "%lld", value);

    return AppFile_writeStr(pcFileName, szValue);
}

/**********************************************************
 * Function Name:        AppFile_ReadStr
 * Description:          文件读取字符串
 * Parameters[in]:       IN const CHAR *pcFileName
 *                       INOUT CHAR * pcValue
 *                       IN SINT32 s32Size
 * Parameters[out]:      INOUT CHAR * pcValue
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
 * Note:                 适用于读内存中文件
***********************************************************/
ULONG AppFile_ReadStr(IN const CHAR *pcFileName, INOUT CHAR * pcValue, IN SINT32 s32Size)
{
    SINT32 fd = -1;
    SINT32 iRet = 0;

    fd = open(pcFileName, O_RDONLY);
    if(fd < 0)
    {
        LOG_ERROR("open %s fail, Error %s\n", pcFileName, strerror(errno));
        return STAT_ERR_FILE_OPEN;
    }

    AppFile_rdlock_block(fd);
    iRet = read(fd, (void *)pcValue, s32Size - 1);
    AppFile_unlock(fd);
    close(fd);

    if (iRet < 0)
    {
        LOG_ERROR("read %s fail, Error %s\n", pcFileName, strerror(errno));
        return STAT_ERR_FILE_READ;
    }

    return STAT_SUCCESS;
}

/**********************************************************
 * Function Name:        AppFile_ReadInt32
 * Description:          文件读取32位整型
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_ReadInt32(const CHAR *pcFileName, SINT32 *value)
{
    CHAR szValue[64] = {0};
    ULONG uRet = 0;

    uRet = AppFile_ReadStr(pcFileName, szValue, sizeof(szValue));
    if (uRet != STAT_SUCCESS)
    {
        LOG_ERROR("AppFile_ReadStr %s fail\n", pcFileName);
        return uRet;
    }

    sscanf(szValue, "%d", value);

    return STAT_SUCCESS; 
}

/**********************************************************
 * Function Name:        AppFile_ReadInt64
 * Description:          文件读取64位整型
 * Parameters[in]:       IN SINT32 fd
 * Parameters[out]:      
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.10
***********************************************************/
ULONG AppFile_ReadInt64(const char *pcFileName, SINT64 *value)
{
    CHAR szValue[64] = {0};
    ULONG uRet = 0;

    uRet = AppFile_ReadStr(pcFileName, szValue, sizeof(szValue));
    if (uRet != STAT_SUCCESS)
    {
        LOG_ERROR("AppFile_ReadStr %s fail\n", pcFileName);
        return uRet;
    }

    sscanf(szValue, "%lld", value);

    return STAT_SUCCESS;
}

